#include "StdAfx.h"
#include "ueh.h"
#include <dbghelp.h>

typedef BOOL ( WINAPI * PFN_MiniDumpWriteDump )(
  HANDLE hProcess,
  DWORD ProcessId,
  HANDLE hFile,
  MINIDUMP_TYPE DumpType,
  PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
  PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
  PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);


BOOL WriteMiniDump( PEXCEPTION_POINTERS const pExpPtrs )
{
	HMODULE hDbgHelp = ::LoadLibrary( TEXT("DBGHELP.DLL") );
	if( !hDbgHelp )
	{
		return FALSE;
	}

    PFN_MiniDumpWriteDump pfnMiniDump = reinterpret_cast<PFN_MiniDumpWriteDump>(
		GetProcAddress( hDbgHelp, "MiniDumpWriteDump" ) );
    if( !pfnMiniDump )
    {
		::FreeLibrary( hDbgHelp );
		return FALSE;
	}

    MINIDUMP_EXCEPTION_INFORMATION sDumpInfo;
    HANDLE hDumpFile;
    
    sDumpInfo.ThreadId = GetCurrentThreadId();
    sDumpInfo.ExceptionPointers = pExpPtrs;
    sDumpInfo.ClientPointers = 0;

	hDumpFile = CreateFileW(
		g_csUtProjCommandLineParser.GetDumpPath(),
		GENERIC_WRITE,
		0, 
		NULL,
		CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,
		NULL );

	pfnMiniDump(
		::GetCurrentProcess(),
		::GetCurrentProcessId(),
		hDumpFile,
		MiniDumpNormal,
		( pExpPtrs ) ? &sDumpInfo : NULL,
		NULL,
		NULL);

	::CloseHandle( hDumpFile );
	::FreeLibrary( hDbgHelp );
	return TRUE;
}

// Unhandled exception filter
LONG WINAPI _UnhandledExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
{
	WriteMiniDump( ExceptionInfo );

	return EXCEPTION_EXECUTE_HANDLER;
}

// Previous top level exception handler
LPTOP_LEVEL_EXCEPTION_FILTER _m_lpHandlerPrev;

// Initialization routine
void UEH_Initialization()
{
	// Hooking internal process exceptions
	_m_lpHandlerPrev = SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)_UnhandledExceptionFilter);

	// No error window
	SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);

	//remove a previously created dmp file if any
	UEH_CleanDmp();
}

// Terminating hooks
void UEH_Termination()
{
	// Restoring exception handler
	SetUnhandledExceptionFilter(_m_lpHandlerPrev);

	SetErrorMode(0);
}

void UEH_CleanDmp()
{
	DeleteFile(g_csUtProjCommandLineParser.GetDumpPath());
}
